package com.amumu.drama.portal.component;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.amumu.drama.common.commpont.notify.OrderNotifyUtils;
import com.amumu.drama.common.config.ScheduledTaskUtil;
import com.amumu.drama.common.constant.DeliveryStatusEnum;
import com.amumu.drama.common.constant.OperateTypeEnum;
import com.amumu.drama.common.constant.OrderTypeEnum;
import com.amumu.drama.common.constant.PayStatusEnum;
import com.amumu.drama.common.modules.delivery.dto.DeliveryOrderStatusQueryResp;
import com.amumu.drama.common.modules.delivery.dto.DeliveryStatusResp;
import com.amumu.drama.common.modules.delivery.service.DeliveryService;
import com.amumu.drama.common.modules.order.cache.OrderSettingCache;
import com.amumu.drama.common.modules.order.dto.req.QueryPayStatusReq;
import com.amumu.drama.common.modules.order.manager.OrderManager;
import com.amumu.drama.common.modules.order.service.OmsPortalOrderService;
import com.amumu.drama.common.modules.order.service.PaymentService;
import com.amumu.drama.common.modules.service.impl.payment.PaymentResp;
import com.amumu.drama.common.utils.date.DatetimeUtils;
import com.amumu.drama.mapper.OmsOrderMapper;
import com.amumu.drama.model.OmsOrder;
import com.amumu.drama.model.OmsOrderSetting;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 取消超时订单并解锁库存的定时器
 * Created by macro on 2018/8/24.
 */
@Slf4j
@Component
public class OrderTimeOutCancelTask {
    @Autowired
    private OmsPortalOrderService portalOrderService;
    @Autowired
    private OmsOrderMapper orderMapper;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private OrderManager orderManager;
    @Autowired
    private DeliveryService deliveryService;

    @PostConstruct
    public void scanOrder() {
        ScheduledTaskUtil.scheduledTask(this::scanOrderForPayStatus, 40, 2 * 60, TimeUnit.SECONDS, "支付超时扫描任务");
        ScheduledTaskUtil.scheduledTask(this::scanOrderForDeliveryStatus, 100, 2 * 60, TimeUnit.SECONDS, "发货超时扫描任务");
    }

    /**
     * cron表达式：Seconds Minutes Hours DayofMonth Month DayofWeek [Year]
     * 每10分钟扫描一次，扫描超时未支付订单，进行取消操作
     */
    public void scanOrderForPayStatus() {
        //扫描超时未支付和支付中的订单，查询支付状态和关闭订单
        log.debug("开始扫描超时未支付订单和支付中订单");
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            List<Integer> queryPayStatusList = Lists.newArrayList(PayStatusEnum.WAIT_PAY.getCode(),
                    PayStatusEnum.PAYING.getCode(),
                    PayStatusEnum.REFUNDING.getCode()
            );

            QueryWrapper<OmsOrder> minIdQueryWrapper = new QueryWrapper<>();
            minIdQueryWrapper.in("pay_status", queryPayStatusList)
                    .eq("delete_status", 0);
            Long minId = orderMapper.selectMinId(minIdQueryWrapper);
            if (minId == null) {
                stopWatch.stop();
                log.info("无超时支付的订单，耗时：{}秒", stopWatch.getTotalTimeSeconds());
                return;
            }
            Long total = 0L;
            List<OmsOrder> omsOrderList = null;
            //分页查询需要处理的订单
            Integer pageSize = 10;
            do {
                omsOrderList = orderMapper.selectList(new LambdaQueryWrapper<OmsOrder>()
                        .ge(omsOrderList == null, OmsOrder::getId, minId)
                        .gt(omsOrderList != null, OmsOrder::getId, minId)
                        .in(OmsOrder::getPayStatus, queryPayStatusList)
                        .eq(OmsOrder::getDeleteStatus, 0)
                        .orderByAsc(OmsOrder::getId)
                        .last("limit " + pageSize));

                if (CollUtil.isEmpty(omsOrderList)) {
                    break;
                }
                for (OmsOrder omsOrder : omsOrderList) {
                    //判断未支付订单是否超时
                    if ((Objects.equals(PayStatusEnum.WAIT_PAY.getCode(), omsOrder.getPayStatus()) || (Objects.equals(PayStatusEnum.PAYING.getCode(), omsOrder.getPayStatus()))) &&
                            DateUtil.between(DatetimeUtils.toDateTime(omsOrder.getCreateTime()), new Date(), DateUnit.MINUTE) > OrderSettingCache.INSTANCE.getValue(OmsOrderSetting::getNormalOrderOvertime)) {
                        //更新订单为订单超时关闭
                        PaymentResp paymentResp = new PaymentResp();
                        paymentResp.setPayStatusEnum(PayStatusEnum.FAIL);
                        paymentResp.setPayRemark("订单超时系统关闭");
                        orderManager.updateOrderPayStatus(omsOrder.getId(), paymentResp, OperateTypeEnum.SYSTEM, omsOrder.getMemberId());
                    } else if ((Objects.equals(PayStatusEnum.PAYING.getCode(), omsOrder.getPayStatus()))) {
                        //查询支付中订单结果
                        QueryPayStatusReq queryPayStatusReq = new QueryPayStatusReq();
                        queryPayStatusReq.setOrderId(omsOrder.getId());
                        paymentService.queryPayStatus(queryPayStatusReq, OperateTypeEnum.SYSTEM, null);
                        ThreadUtil.safeSleep(1000);
                    } else if ((Objects.equals(PayStatusEnum.REFUNDING.getCode(), omsOrder.getPayStatus()))) {
                        //查询退款中订单结果
                        QueryPayStatusReq queryPayStatusReq = new QueryPayStatusReq();
                        queryPayStatusReq.setOrderId(omsOrder.getId());
                        paymentService.queryRefundStatus(queryPayStatusReq, OperateTypeEnum.SYSTEM, null);
                        ThreadUtil.safeSleep(1000);
                    }
                }
                minId = omsOrderList.get(omsOrderList.size() - 1).getId();
                total += omsOrderList.size();
            } while (CollUtil.isNotEmpty(omsOrderList) && omsOrderList.size() == pageSize);
            stopWatch.stop();
            log.info("扫描超时和支付中订单完成,共处理订单:{},共耗时:{}s", total, stopWatch.getTotalTimeSeconds());
        } catch (Exception e) {
            log.error("扫描超时和支付中订单失败：", e);
        }
    }


    /**
     * 轮询查询接口发货中的订单,及时更新状态
     */
    public void scanOrderForDeliveryStatus() {
        //扫描超时未支付和支付中的订单，查询支付状态和关闭订单
        log.debug("开始扫描订单:更新发货状态");
        List<Integer> deliveryStatusList = Lists.newArrayList(DeliveryStatusEnum.WAIT_DELIVERY.getCode(),
                DeliveryStatusEnum.DELIVERY.getCode());
        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            QueryWrapper<OmsOrder> minIdQueryWrapper = new QueryWrapper<>();
            minIdQueryWrapper.in("delivery_status", deliveryStatusList)
//                    .in("order_type", OrderTypeEnum.INTERFACE_DELIVERY.getCode(), OrderTypeEnum.MANUAL2INTERFACE_DELIVERY.getCode())
                    .eq("delete_status", 0);
            Long minId = orderMapper.selectMinId(minIdQueryWrapper);
            if (minId == null) {
                stopWatch.stop();
                log.info("无超时发货的订单，耗时：{}秒", stopWatch.getTotalTimeSeconds());
                return;
            }
            Long total = 0L;
            int manualOrderCount = 0;
            int delayOrderCount = 0;
            List<OmsOrder> omsOrderList = null;
            //分页查询需要处理的订单
            Integer pageSize = 10;
            Integer manualOrderDeliveryDelayOvertime = OrderSettingCache.INSTANCE.getValue(OmsOrderSetting::getManualOrderDeliveryDelayOvertime);
            Integer changerManualOrderTypeOvertime = OrderSettingCache.INSTANCE.getValue(OmsOrderSetting::getChangerManualOrderTypeOvertime);
            Integer deliveryDelayQueryOvertime = OrderSettingCache.INSTANCE.getValueAndDefault(OmsOrderSetting::getDeliveryDelayQueryOvertime, 0);
            do {
                omsOrderList = orderMapper.selectList(new LambdaQueryWrapper<OmsOrder>()
                        .ge(omsOrderList == null, OmsOrder::getId, minId)
                        .gt(omsOrderList != null, OmsOrder::getId, minId)
                        .in(OmsOrder::getDeliveryStatus, deliveryStatusList)
//                        .in(OmsOrder::getOrderType, OrderTypeEnum.INTERFACE_DELIVERY.getCode(), OrderTypeEnum.MANUAL2INTERFACE_DELIVERY.getCode())
                        .eq(OmsOrder::getDeleteStatus, 0)
                        .orderByAsc(OmsOrder::getId)
                        .last("limit " + pageSize));

                if (CollUtil.isEmpty(omsOrderList)) {
                    break;
                }
                for (OmsOrder omsOrder : omsOrderList) {
                    //发货中订单,超时未更新结果时主动轮训
                    if ((Objects.equals(PayStatusEnum.SUCCESS.getCode(), omsOrder.getPayStatus())) &&
                            OrderTypeEnum.isInterface(omsOrder.getOrderType()) &&
                            DeliveryStatusEnum.idDelivery(omsOrder.getDeliveryStatus()) &&
                            DateUtil.between(DatetimeUtils.toDateTime(omsOrder.getDeliveryTime()), new Date(), DateUnit.SECOND) > deliveryDelayQueryOvertime) {
                        //轮询查询发货状态
                        DeliveryOrderStatusQueryResp deliveryStatus = deliveryService.pollQueryDeliveryStatus(omsOrder.getId(), omsOrder, OperateTypeEnum.SYSTEM, omsOrder.getMemberId(), true);
                        //持续发挥中状态，超时转人工
                        Long between = DatetimeUtils.between(omsOrder.getCreateTime(), LocalDateTime.now(), DateUnit.SECOND);
                        if (changerManualOrderTypeOvertime != null && changerManualOrderTypeOvertime != 0 && DeliveryStatusEnum.DELIVERY.equals(deliveryStatus.getDeliveryStatusEnum()) &&
                                OrderTypeEnum.INTERFACE_DELIVERY.getCode().equals(omsOrder.getOrderType())
                                && between != null && between >= Long.valueOf(changerManualOrderTypeOvertime)) {
                            //转人工接口
                            DeliveryStatusResp deliveryStatusResp = deliveryStatus.getDeliveryStatusResp();
                            deliveryStatusResp.setMsg(StrUtil.format("接口订单超市转人工，超时时间{}秒", between));
                            orderManager.changeOrderType(omsOrder, deliveryStatusResp, OrderTypeEnum.MANUAL_DELIVERY, OperateTypeEnum.SYSTEM, null);
                            manualOrderCount++;
                        }

                    } else if (Objects.equals(PayStatusEnum.SUCCESS.getCode(), omsOrder.getPayStatus()) &&
                            OrderTypeEnum.isManual(omsOrder.getOrderType()) &&
                            DeliveryStatusEnum.isWaitDelivery(omsOrder.getDeliveryStatus()) &&
                            manualOrderDeliveryDelayOvertime != null &&
                            DatetimeUtils.between(omsOrder.getCreateTime(), LocalDateTime.now(), DateUnit.MINUTE) > manualOrderDeliveryDelayOvertime) {
                        //todo 人工订单超时未发货，飞书发通知
                        OrderNotifyUtils.manualOrderDelayNotify(omsOrder);
                        delayOrderCount++;

                    }
                }
                minId = omsOrderList.get(omsOrderList.size() - 1).getId();
                total += omsOrderList.size();
            } while (CollUtil.isNotEmpty(omsOrderList) && omsOrderList.size() == pageSize);
            stopWatch.stop();
            log.info("扫描发货中订单完成,共处理订单:{},发货超时转人工订单:{},人工超时订单:{}共耗时:{}s", total, manualOrderCount, delayOrderCount, stopWatch.getTotalTimeSeconds());
        } catch (Exception e) {
            log.error("扫描发货中订单失败：", e);
        }
    }
}
